package com.jiashn.minio.utils;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.jiashn.minio.config.PearMinioClient;
import com.jiashn.minio.domain.vo.MinioPearVo;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Part;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author: jiangjs
 * @description: minio分片上传工具
 * @date: 2023/10/30 9:34
 **/
@Component
@Slf4j
public class MinioPearUploadUtil {

    @Resource
    private PearMinioClient pearMinioClient;

    /**
     * 校验当前bucket是否存在，不存在则创建
     * @param bucketName 桶
     */
    private void existBucket(String bucketName){
        try {
            boolean isExist = pearMinioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!isExist){
                pearMinioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 创建分片上传信息
     * @param chunkNum 分片数量
     * @param fileName 文件名称
     * @param contentType 文件类型
     * @param bucketEnum 桶
     * @return 返回分片信息
     */
    @SneakyThrows
    public MinioPearVo createMultipartUploadUrl(Integer chunkNum, String fileName, String contentType,MinioBucketEnum bucketEnum){
        //设置分片文件类型
        Multimap<String, String> headerMap = HashMultimap.create();
        headerMap.put("Content-Type",contentType);
        CreateMultipartUploadResponse uploadResponse = pearMinioClient.createMultipartUpload(bucketEnum.getBucket(), null, fileName,
                headerMap, null);
        Map<String, String> reqParams = new HashMap<>(2);
        reqParams.put("uploadId",uploadResponse.result().uploadId());
        MinioPearVo pearVo = new MinioPearVo();
        pearVo.setUploadId(uploadResponse.result().uploadId());
        List<MinioPearVo.PearUploadData> uploads = new ArrayList<>();
        for (int i = 1; i <= chunkNum; i++) {
            reqParams.put("partNumber",String.valueOf(i));
            String objectUrl = pearMinioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.PUT)
                            .bucket(MinioBucketEnum.EMAIL.getBucket())
                            .object(fileName)
                            .expiry(1, TimeUnit.DAYS)
                            .extraQueryParams(reqParams)
                            .build());
            MinioPearVo.PearUploadData uploadData = new MinioPearVo.PearUploadData();
            uploadData.setUploadUrl(objectUrl).setParkNum(i);
            uploads.add(uploadData);
        }
        pearVo.setParts(uploads);
        return pearVo;
    }

    /**
     * 合并文件分片
     * @param chunkNum 分片数量
     * @param fileName 文件名称
     * @param contentType 文件类型
     * @param uploadId 分片上传时的Id
     * @param bucketEnum 桶
     * @return 合并结果
     */
    @SneakyThrows
    public Boolean completeMultipart(Integer chunkNum, String fileName, String contentType,String uploadId,MinioBucketEnum bucketEnum){
        Multimap<String, String> headerMap = HashMultimap.create();
        headerMap.put("Content-Type",contentType);
        ListPartsResponse listMultipart = pearMinioClient.listMultipart(bucketEnum.getBucket(), null, fileName, chunkNum + 10,
                0, uploadId, headerMap, null);
        if (Objects.nonNull(listMultipart)){
            Part[] parts = new Part[chunkNum+10];
            int partNum = 1;
            for (Part part : listMultipart.result().partList()) {
                parts[partNum -1] = new Part(partNum,part.etag());
                partNum++;
            }
            pearMinioClient.completeMultipartUpload(MinioBucketEnum.EMAIL.getBucket(), null, fileName,
                    uploadId, parts, headerMap, null);
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 文件流上传
     * @param ism 文件流
     * @param bucketName 桶名称
     * @param fileName 文件名称
     * @return 执行结果
     */
    public Boolean upLoadInputStream(InputStream ism, String bucketName, String fileName){
        try {
            existBucket(bucketName);
            pearMinioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(ism,ism.available(),-1)
                    .build());
            return Boolean.TRUE;
        }catch (Exception e){
            log.error("文件流上传报错："+e.getMessage());
            e.printStackTrace();
            return Boolean.FALSE;
        }
    }

    /**
     * 下载文件
     * @param fileName 文件名称
     * @param bucketName 桶名称
     * @return 文件流
     */
    public InputStream downLoadFile(String fileName,String bucketName){
        InputStream ism = null;
        try {
            ism = pearMinioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName).build());
        } catch (Exception e) {
            log.error(String.format("下载文件（%s）报错：%s",fileName,e.getMessage()));
            e.printStackTrace();
        }
        return ism;
    }
}
